#include "Threat.h"

std::list<int> playerReferences;
std::list<GomokuBoard> boardReferences;
std::list<std::list<Threat>> threatReferences;

void Threat::Print(std::ostream &stream)
{
	stream << "Threat Type: ";
	switch(m_type)
	{
	case THREAT_FIVE:
		stream << "Five";
	break;

	case THREAT_FOUR:
		stream << "Four";
	break;

	case THREAT_FOUR_STRAIGHT:
		stream << "Straight Four";
	break;

	case THREAT_THREE:
		stream << "Three";
	break;
	}

	stream << "\n" << "Gain Square: (" << m_gainSquare[0] << ", " << m_gainSquare[1] << ")\n";

	stream << m_costSquares.size() << " Cost Squares:\n";
	for(std::list<int*>::iterator it = m_costSquares.begin(); it != m_costSquares.end(); it++)
	{
		stream << "(" << (*it)[0] << ", " << (*it)[1] << ")\n";
	}

	stream << "\n";
}

void Threat::Write(std::ostream &stream)
{
	stream << m_type << "\n" << m_gainSquare[0] << "\n" << m_gainSquare[1] << "\n" << m_costSquares.size() << "\n";

	for(std::list<int*>::iterator it = m_costSquares.begin(); it != m_costSquares.end(); it++)
	{
		stream << (*it)[0] << "\n" << (*it)[1] << "\n";
	}

	stream << "\n";
}

void Threat::Parse(std::istream &stream)
{
	std::stringbuf t_buffer;

	stream.get(t_buffer);

	std::stringstream t_stream(t_buffer.str());

	char t_type[20];
	char t_gain0[20];
	char t_gain1[20];
	char t_costSize[20];
	int t_costSquareSize;

	t_stream.get(t_type, 20);
	switch(atoi(t_type))
	{
	case 0:
		m_type = THREAT_FIVE;
	break;

	case 1:
		m_type = THREAT_FOUR_STRAIGHT;
	break;

	case 2:
		m_type = THREAT_FOUR;
	break;

	case 3:
		m_type = THREAT_THREE;
	break;
	}
	t_stream.ignore();

	t_stream.get(t_gain0, 20);
	m_gainSquare[0] = atoi(t_gain0);
	t_stream.ignore();

	t_stream.get(t_gain1, 20);
	m_gainSquare[1] = atoi(t_gain1);
	t_stream.ignore();

	t_stream.get(t_costSize, 20);
	t_costSquareSize = atoi(t_costSize);
	t_stream.ignore();

	for(int a = 0; a < t_costSquareSize; a++)
	{
		char t_number0[20];
		char t_number1[20];
		int *t_costSquare = new int[2];

		t_stream.get(t_number0, 20);
		t_costSquare[0] = atoi(t_number0);
		t_stream.ignore();

		t_stream.get(t_number1, 20);
		t_costSquare[1] = atoi(t_number1);
		t_stream.ignore();

		m_costSquares.push_back(t_costSquare);
	}
}

bool ThreatCompare(Threat threat0, Threat threat1)
{
	if(threat0.m_type < threat1.m_type) return true;
	return false;
}

void SaveThreatReference(std::string name)
{
	remove(name.c_str());

	std::fstream t_stream(name.c_str());
	
	std::list<int>::iterator t_playerIt = playerReferences.begin();
	std::list<GomokuBoard>::iterator t_boardIt = boardReferences.begin();
	std::list<std::list<Threat>>::iterator t_threatsIt = threatReferences.begin();

	while(t_playerIt != playerReferences.end() && t_boardIt != boardReferences.end() && t_threatsIt != threatReferences.end())
	{
		t_stream << (*t_playerIt) << "\n";

		(*t_boardIt).Write(t_stream);

		t_stream << (*t_threatsIt).size() << "\n";

		for(std::list<Threat>::iterator it = (*t_threatsIt).begin(); it != (*t_threatsIt).end(); it++)
		{
			(*it).Write(t_stream);
		}

		t_boardIt++;
		t_threatsIt++;
	}
}

void LoadThreatReference(std::string name)
{
	std::fstream t_stream(name.c_str());

	while(!t_stream.eof())
	{
		char t_playerString[20];

		t_stream.get(t_playerString, 20);
		int t_player = atoi(t_playerString);
		t_stream.ignore();

		GomokuBoard *t_board = new GomokuBoard(t_stream);

		boardReferences.push_back(*t_board);

		char t_threatCountString[20];

		t_stream.get(t_threatCountString, 20);
		int t_threatCount = atoi(t_threatCountString);
		t_stream.ignore();
		
		std::list<Threat> *t_threats = new std::list<Threat>;

		for(int a = 0; a < t_threatCount; a++)
		{
			Threat *t_newThreat = new Threat;
			t_newThreat->Parse(t_stream);
			t_threats->push_back(*t_newThreat);
		}

		threatReferences.push_back(*t_threats);
	}
}

void AddThreatReference(int player, Board board, std::list<Threat> threats)
{
	playerReferences.push_back(player);
	boardReferences.push_back(board);
	threatReferences.push_back(threats);
}

bool SearchThreatReference(int player, Board board, std::list<Threat> &threats)
{
	std::list<int>::iterator t_playerIt = playerReferences.begin();
	std::list<GomokuBoard>::iterator t_boardIt = boardReferences.begin();
	std::list<std::list<Threat>>::iterator t_threatsIt = threatReferences.begin();

	while(t_playerIt != playerReferences.end() && t_boardIt != boardReferences.end() && t_threatsIt != threatReferences.end())
	{
		bool t_compare = (*t_playerIt) == player;

		for(int a = 0; a < 19; a++) for(int b = 0; b < 19; b++)
		{
			if(board[a][b] != (*t_boardIt).Get(a, b)) t_compare = false;
		}

		if(t_compare)
		{
			threats = (*t_threatsIt);
			return true;
		}

		t_boardIt++;
		t_threatsIt++;
	}

	return false;
}

void FindAllThreats(int player, Board board, std::list<Threat> &threats)
{
	/*if(SearchThreatReference(player, board, threats))
	{
		return;
	}
	else
	{*/
		HorizontalGetter t_horGetter;
		VerticalGetter t_verGetter;
		UpToDownDiagonalGetter t_upDownGetter;
		DownToUpDiagonalGetter t_downUpGetter;

		// Check Horizontal
		FindThreats(t_horGetter, player, board, threats);

		// Check Vertical
		FindThreats(t_verGetter, player, board, threats);

		// Check Diagonal
		FindThreats(t_upDownGetter, player, board, threats);
		FindThreats(t_downUpGetter, player, board, threats);

		// Check for errors
		std::list<Threat>::iterator it = threats.begin();

		while(true)
		{
			if(it == threats.end()) break;

			bool t_erase = false;
			
			if((*it).m_gainSquare[0] < 0 || (*it).m_gainSquare[0] > 18 || (*it).m_gainSquare[1] < 0 || (*it).m_gainSquare[1] > 18)
				t_erase = true;
			else if(board[(*it).m_gainSquare[0]][(*it).m_gainSquare[1]] != 0)
				t_erase = true;
			
			for(std::list<int*>::iterator it2 = (*it).m_costSquares.begin(); it2 != (*it).m_costSquares.end(); it2++)
			{
				if((*it2)[0] < 0 || (*it2)[0] > 18 || (*it2)[1] < 0 || (*it2)[1] > 18)
					t_erase = true;
				else if(board[(*it2)[0]][(*it2)[1]] != 0)
					t_erase = true;
			}

			if(t_erase) it = threats.erase(it);
			else it++;
		}

	/*	AddThreatReference(player, board, threats);
	}*/
}

void FindThreats(CoordinateGetter &getter, int player, Board board, std::list<Threat> &threats)
{
	GomokuBoard t_board(board);
	Threat* t_newThreat;

	int t_opponent;
	if(player == 1) t_opponent = 2;
	else t_opponent = 1;

	for(int a = 0; a < 19; a++)
	{
		for(int b = 0; b < 19; b++)
		{
			// Find Fives
			bool t_goodCoordinates = true;
			int t_numberInRow = 0;
			for(int c = 0; c < 5; c++)
			{
				int t_x = getter.GetX(a, b, c);
				int t_y = getter.GetY(a, b, c);

				if(!t_board.InBounds(t_x, t_y))
					t_goodCoordinates = false;
				else if(t_board.Get(t_x, t_y) == player)
					t_numberInRow++;
			}

			// Possible five
			if(t_goodCoordinates && t_numberInRow == 4)
			{
				int t_xn2, t_yn2, t_xn1, t_yn1, t_x0, t_y0, t_x1, t_y1, t_x2, t_y2, t_x3, t_y3, t_x4, t_y4, t_x5, t_y5, t_x6, t_y6;
				t_xn2 = getter.GetX(a, b, -2);
				t_yn2 = getter.GetY(a, b, -2);
				t_xn1 = getter.GetX(a, b, -1);
				t_yn1 = getter.GetY(a, b, -1);
				t_x0 = getter.GetX(a, b, 0);
				t_y0 = getter.GetY(a, b, 0);
				t_x1 = getter.GetX(a, b, 1);
				t_y1 = getter.GetY(a, b, 1);
				t_x2 = getter.GetX(a, b, 2);
				t_y2 = getter.GetY(a, b, 2);
				t_x3 = getter.GetX(a, b, 3);
				t_y3 = getter.GetY(a, b, 3);
				t_x4 = getter.GetX(a, b, 4);
				t_y4 = getter.GetY(a, b, 4);
				t_x5 = getter.GetX(a, b, 5);
				t_y5 = getter.GetY(a, b, 5);
				t_x6 = getter.GetX(a, b, 6);
				t_y6 = getter.GetY(a, b, 6);

				if(t_board.Get(t_x1, t_y1) != t_opponent && t_board.Get(t_x2, t_y2) != t_opponent && t_board.Get(t_x3, t_y3) != t_opponent)
				{
					if(t_board.Get(t_x0, t_y0) == t_opponent)
					{
						if(t_board.Get(t_x5, t_y5) == 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FIVE;
							t_newThreat->m_gainSquare[0] = t_x5;
							t_newThreat->m_gainSquare[1] = t_y5;
							threats.push_back(*t_newThreat);
							break;
						}
					}

					if(t_board.Get(t_x4, t_y4) == t_opponent)
					{
						if(t_board.Get(t_xn1, t_yn1) == 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FIVE;
							t_newThreat->m_gainSquare[0] = t_xn1;
							t_newThreat->m_gainSquare[1] = t_yn1;
							threats.push_back(*t_newThreat);
							break;
						}
					}

					if(t_board.Get(t_x0, t_y0) == 0)
					{
						if(t_board.Get(t_x5, t_y5) != 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FIVE;
							t_newThreat->m_gainSquare[0] = t_x0;
							t_newThreat->m_gainSquare[1] = t_y0;
							threats.push_back(*t_newThreat);
						}

						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FIVE;
						t_newThreat->m_gainSquare[0] = t_x5;
						t_newThreat->m_gainSquare[1] = t_y5;
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_x4, t_y4) == 0)
					{
						if(t_board.Get(t_x0, t_y0) != 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FIVE;
							t_newThreat->m_gainSquare[0] = t_x4;
							t_newThreat->m_gainSquare[1] = t_y4;
							threats.push_back(*t_newThreat);
						}

						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FIVE;
						t_newThreat->m_gainSquare[0] = t_x0;
						t_newThreat->m_gainSquare[1] = t_y0;
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_x1, t_y1) == 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FIVE;
						t_newThreat->m_gainSquare[0] = t_x1;
						t_newThreat->m_gainSquare[1] = t_y1;
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_x2, t_y2) == 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FIVE;
						t_newThreat->m_gainSquare[0] = t_x2;
						t_newThreat->m_gainSquare[1] = t_y2;
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_x3, t_y3) == 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FIVE;
						t_newThreat->m_gainSquare[0] = t_x3;
						t_newThreat->m_gainSquare[1] = t_y3;
						threats.push_back(*t_newThreat);
						break;
					}
				}
			}
			// End Find Fives

			// Find Fours
			t_goodCoordinates = true;
			t_numberInRow = 0;
			for(int c = 0; c < 3; c++)
			{
				int t_x = getter.GetX(a, b, c);
				int t_y = getter.GetY(a, b, c);

				if(!t_board.InBounds(t_x, t_y))
					t_goodCoordinates = false;
				else if(t_board.Get(t_x, t_y) == player)
					t_numberInRow++;
			}

			// Possible Four Threat
			if(t_goodCoordinates && t_numberInRow == 3)
			{
				int t_xn2, t_yn2, t_xn1, t_yn1, t_x0, t_y0, t_x1, t_y1, t_x2, t_y2, t_x3, t_y3, t_x4, t_y4;
				t_xn2 = getter.GetX(a, b, -2);
				t_yn2 = getter.GetY(a, b, -2);
				t_xn1 = getter.GetX(a, b, -1);
				t_yn1 = getter.GetY(a, b, -1);
				t_x0 = getter.GetX(a, b, 0);
				t_y0 = getter.GetY(a, b, 0);
				t_x1 = getter.GetX(a, b, 1);
				t_y1 = getter.GetY(a, b, 1);
				t_x2 = getter.GetX(a, b, 2);
				t_y2 = getter.GetY(a, b, 2);
				t_x3 = getter.GetX(a, b, 3);
				t_y3 = getter.GetY(a, b, 3);
				t_x4 = getter.GetX(a, b, 4);
				t_y4 = getter.GetY(a, b, 4);
				
				// Threat may exist, find type
				if(t_board.Get(t_xn1, t_yn1) == 0 || t_board.Get(t_x3, t_y3) == 0)
				{
					if(t_board.Get(t_xn1, t_yn1) != 0 && t_board.Get(t_x4, t_y4) == 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_x3;
						t_newThreat->m_gainSquare[1] = t_y3;
						int* t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_x4;
						t_newCostSquare[1] = t_y4;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_x3, t_y3) != 0 && t_board.Get(t_xn2, t_yn2) == 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_xn1;
						t_newThreat->m_gainSquare[1] = t_yn1;
						int* t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_xn2;
						t_newCostSquare[1] = t_yn2;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_xn2, t_yn2) != 0 && t_board.Get(t_x4, t_y4) != 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_xn1;
						t_newThreat->m_gainSquare[1] = t_yn1;
						int* t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_x3;
						t_newCostSquare[1] = t_y3;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);

						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_x3;
						t_newThreat->m_gainSquare[1] = t_y3;
						t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_xn1;
						t_newCostSquare[1] = t_yn1;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);
						break;
					}

					if(t_board.Get(t_xn2, t_yn2) != 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_xn1;
						t_newThreat->m_gainSquare[1] = t_yn1;
						int* t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_x3;
						t_newCostSquare[1] = t_y3;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);

						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
						t_newThreat->m_gainSquare[0] = t_x3;
						t_newThreat->m_gainSquare[1] = t_y3;
						threats.push_back(*t_newThreat);
						break;
					}
					
					if(t_board.Get(t_x4, t_y4) != 0)
					{
						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR;
						t_newThreat->m_gainSquare[0] = t_x3;
						t_newThreat->m_gainSquare[1] = t_y3;
						int* t_newCostSquare = new int[2];
						t_newCostSquare[0] = t_xn1;
						t_newCostSquare[1] = t_yn1;
						t_newThreat->m_costSquares.push_back(t_newCostSquare);
						threats.push_back(*t_newThreat);

						t_newThreat = new Threat;
						t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
						t_newThreat->m_gainSquare[0] = t_xn1;
						t_newThreat->m_gainSquare[1] = t_yn1;
						threats.push_back(*t_newThreat);
						break;
					}
				}
				
				t_newThreat = new Threat;
				t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
				t_newThreat->m_gainSquare[0] = t_xn1;
				t_newThreat->m_gainSquare[1] = t_yn1;
				threats.push_back(*t_newThreat);

				t_newThreat = new Threat;
				t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
				t_newThreat->m_gainSquare[0] = t_x3;
				t_newThreat->m_gainSquare[1] = t_y3;
				threats.push_back(*t_newThreat);
				break;
			}

			// Find Spaced fours
			t_goodCoordinates = true;
			t_numberInRow = 0;
			for(int c = 0; c < 4; c++)
			{
				int t_x = getter.GetX(a, b, c);
				int t_y = getter.GetY(a, b, c);

				if(!t_board.InBounds(t_x, t_y))
					t_goodCoordinates = false;
				else if(t_board.Get(t_x, t_y) == player)
					t_numberInRow++;
			}

			// Possible four
			if(t_goodCoordinates && t_numberInRow == 3)
			{
				int t_xn2, t_yn2, t_xn1, t_yn1, t_x0, t_y0, t_x1, t_y1, t_x2, t_y2, t_x3, t_y3, t_x4, t_y4;
				t_xn2 = getter.GetX(a, b, -2);
				t_yn2 = getter.GetY(a, b, -2);
				t_xn1 = getter.GetX(a, b, -1);
				t_yn1 = getter.GetY(a, b, -1);
				t_x0 = getter.GetX(a, b, 0);
				t_y0 = getter.GetY(a, b, 0);
				t_x1 = getter.GetX(a, b, 1);
				t_y1 = getter.GetY(a, b, 1);
				t_x2 = getter.GetX(a, b, 2);
				t_y2 = getter.GetY(a, b, 2);
				t_x3 = getter.GetX(a, b, 3);
				t_y3 = getter.GetY(a, b, 3);
				t_x4 = getter.GetX(a, b, 4);
				t_y4 = getter.GetY(a, b, 4);

				if(t_board.Get(t_x0, t_y0) == player && t_board.Get(t_x3, t_y3) == player)
				{
					if(t_board.Get(t_x1, t_y1) == 0)
					{
						if(t_board.Get(t_xn1, t_yn1) == t_opponent)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR;
							t_newThreat->m_gainSquare[0] = t_x1;
							t_newThreat->m_gainSquare[1] = t_y1;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x4;
							t_newCostSquare[1] = t_y4;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else if(t_board.Get(t_x4, t_y4) == t_opponent)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR;
							t_newThreat->m_gainSquare[0] = t_x1;
							t_newThreat->m_gainSquare[1] = t_y1;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn1;
							t_newCostSquare[1] = t_yn1;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
							t_newThreat->m_gainSquare[0] = t_x1;
							t_newThreat->m_gainSquare[1] = t_y1;
							threats.push_back(*t_newThreat);
						}
						break;
					}

					if(t_board.Get(t_x2, t_y2) == 0)
					{
						if(t_board.Get(t_xn1, t_yn1) == t_opponent)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR;
							t_newThreat->m_gainSquare[0] = t_x2;
							t_newThreat->m_gainSquare[1] = t_y2;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x4;
							t_newCostSquare[1] = t_y4;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else if(t_board.Get(t_x4, t_y4) == t_opponent)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR;
							t_newThreat->m_gainSquare[0] = t_x2;
							t_newThreat->m_gainSquare[1] = t_y2;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn1;
							t_newCostSquare[1] = t_yn1;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_FOUR_STRAIGHT;
							t_newThreat->m_gainSquare[0] = t_x2;
							t_newThreat->m_gainSquare[1] = t_y2;
							threats.push_back(*t_newThreat);
						}
						break;
					}
				}
			}
			// End find fours

			// Find Threes
			if(a > 0 && a < 18 && b > 0 && b < 18)
			{
				t_goodCoordinates = true;
				t_numberInRow = 0;
				for(int c = 0; c < 2; c++)
				{
					int t_x = getter.GetX(a, b, c);
					int t_y = getter.GetY(a, b, c);

					if(!t_board.InBounds(t_x, t_y))
						t_goodCoordinates = false;
					else if(t_board.Get(t_x, t_y) == player)
						t_numberInRow++;
				}

				// Possible Three
				if(t_goodCoordinates && t_numberInRow == 2)
				{
					int t_xn3, t_yn3, t_xn2, t_yn2, t_xn1, t_yn1, t_x0, t_y0, t_x1, t_y1, t_x2, t_y2, t_x3, t_y3, t_x4, t_y4;
					t_xn3 = getter.GetX(a, b, -3);
					t_yn3 = getter.GetY(a, b, -3);
					t_xn2 = getter.GetX(a, b, -2);
					t_yn2 = getter.GetY(a, b, -2);
					t_xn1 = getter.GetX(a, b, -1);
					t_yn1 = getter.GetY(a, b, -1);
					t_x0 = getter.GetX(a, b, 0);
					t_y0 = getter.GetY(a, b, 0);
					t_x1 = getter.GetX(a, b, 1);
					t_y1 = getter.GetY(a, b, 1);
					t_x2 = getter.GetX(a, b, 2);
					t_y2 = getter.GetY(a, b, 2);
					t_x3 = getter.GetX(a, b, 3);
					t_y3 = getter.GetY(a, b, 3);
					t_x4 = getter.GetX(a, b, 4);
					t_y4 = getter.GetY(a, b, 4);

					if(t_board.Get(t_xn1, t_yn1) == 0 && t_board.Get(t_x2, t_y2) == 0)
					{
						if(t_board.Get(t_xn2, t_yn2) != 0 && t_board.Get(t_x3, t_y3) == 0 && t_board.Get(t_x4, t_y4) == 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_THREE;
							t_newThreat->m_gainSquare[0] = t_x2;
							t_newThreat->m_gainSquare[1] = t_y2;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn1;
							t_newCostSquare[1] = t_yn1;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x3;
							t_newCostSquare[1] = t_y3;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x4;
							t_newCostSquare[1] = t_y4;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else if(t_board.Get(t_x3, t_y3) != 0 && t_board.Get(t_xn2, t_yn2) == 0 && t_board.Get(t_xn3, t_yn3) == 0)
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_THREE;
							t_newThreat->m_gainSquare[0] = t_xn1;
							t_newThreat->m_gainSquare[1] = t_yn1;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x2;
							t_newCostSquare[1] = t_y2;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn2;
							t_newCostSquare[1] = t_yn2;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn3;
							t_newCostSquare[1] = t_yn3;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						else
						{
							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_THREE;
							t_newThreat->m_gainSquare[0] = t_xn1;
							t_newThreat->m_gainSquare[1] = t_yn1;
							int* t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x2;
							t_newCostSquare[1] = t_y2;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn2;
							t_newCostSquare[1] = t_yn2;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);

							t_newThreat = new Threat;
							t_newThreat->m_type = THREAT_THREE;
							t_newThreat->m_gainSquare[0] = t_x2;
							t_newThreat->m_gainSquare[1] = t_y2;
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_x3;
							t_newCostSquare[1] = t_y3;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							t_newCostSquare = new int[2];
							t_newCostSquare[0] = t_xn1;
							t_newCostSquare[1] = t_yn1;
							t_newThreat->m_costSquares.push_back(t_newCostSquare);
							threats.push_back(*t_newThreat);
						}
						break;
					}
				}
			}
			// End find threes
		}
	}
}


int FindThreatSequence(int player, Board board, std::list<Threat> threats, int depth, Move &out)
{
	int t_opponent = 1;
	if(player == 1) t_opponent = 2;

	if(threats.empty()) return -1;

	threats.sort(ThreatCompare);

	if(threats.front().m_type == THREAT_FIVE)
	{
		out[0] = threats.front().m_gainSquare[0];
		out[1] = threats.front().m_gainSquare[1];
		return depth;
	}

	if(threats.front().m_type == THREAT_FOUR_STRAIGHT)
	{
		out[0] = threats.front().m_gainSquare[0];
		out[1] = threats.front().m_gainSquare[1];
		return depth + 2;
	}

	std::list<Threat> t_threats;
	Board t_board;

	for(std::list<Threat>::iterator it = threats.begin(); it != threats.end(); it++)
	{
		for(int a = 0; a < 19; a++) for(int b = 0; b < 19; b++) t_board[a][b] = board[a][b];

		t_board[(*it).m_gainSquare[0]][(*it).m_gainSquare[1]] = player;
		
		int t_depth;
		bool t_allCounterMovesGood = true;
		for(std::list<int*>::iterator it2 = (*it).m_costSquares.begin(); it2 != (*it).m_costSquares.end(); it2++)
		{
			t_board[(*it2)[0]][(*it2)[1]] = t_opponent;
			t_threats.clear();
			FindAllThreats(player, t_board, t_threats);
			t_depth = FindThreatSequence(player, t_board, t_threats, depth + 2, out);
			if(t_depth < 0)
			{
				t_allCounterMovesGood = false;
			}
		}

		if(t_allCounterMovesGood)
		{
			out[0] = (*it).m_gainSquare[0];
			out[1] = (*it).m_gainSquare[1];
			return t_depth;
		}
		else return -1;
	}

	return -1;
}

bool CounterOpponentThreat(int player, Board board, std::list<Threat> opponentThreats, Move &out)
{
	int t_opponent = 1;
	if(player == 1) t_opponent = 2;

	std::list<int*> t_forcedMoves;

	if(opponentThreats.empty()) return false;

	opponentThreats.sort(ThreatCompare);

	for(std::list<Threat>::iterator it = opponentThreats.begin(); it != opponentThreats.end(); it++)
	{
		switch((*it).m_type)
		{
		case THREAT_FOUR_STRAIGHT:
			t_forcedMoves.push_back((*it).m_gainSquare);
		break;

		default:
		break;
		}
	}

	if(t_forcedMoves.empty()) return false;

	int *t_bestMove = 0;
	int t_bestValue = 0;
	for(std::list<int*>::iterator it = t_forcedMoves.begin(); it != t_forcedMoves.end(); it++)
	{
		Board t_board;
		for(int a = 0; a < 19; a++) for(int b = 0; b < 19; b++) t_board[a][b] = board[a][b];
		t_board[(*it)[0]][(*it)[1]] = player;

		std::list<Threat> t_threats;
		FindAllThreats(t_opponent, t_board, t_threats);
		
		int t_value = 0;
		for(std::list<Threat>::iterator it2 = t_threats.begin(); it2 != t_threats.end(); it2++)
		{
			switch((*it2).m_type)
			{
			case THREAT_FIVE:
				t_value += 10;
			break;

			case THREAT_FOUR_STRAIGHT:
				t_value += 6;
			break;

			case THREAT_FOUR:
				t_value += 2;
			break;

			case THREAT_THREE:
				t_value += 1;
			break;
			}
		}

		if(t_bestMove == 0)
		{
			t_bestMove = *it;
			t_bestValue = t_value;
		}
		else if(t_value < t_bestValue)
		{
			t_bestMove = *it;
			t_bestValue = t_value;
		}
	}

	out[0] = t_bestMove[0];
	out[1] = t_bestMove[1];
	return true;
}